
#ifndef NOSAL_EXEC_INTERNAL_STATE_CHANGE_HANDLER_H_
#define NOSAL_EXEC_INTERNAL_STATE_CHANGE_HANDLER_H_

//#include "state_client_impl.h"
#include "processed_set_state_request.h"

namespace netaos {
namespace nosal {
namespace exec {
namespace internal {

class StateChangeHandler final
{
public:
    /// @brief Constructor of StateChangeHandler instance.
    ///
    /// @param function_groups A map of all FunctionGroups. Is owned by the ExecutionManager instance.
    /// @param executed_startup_configurations A set of all StartupConfigurations that are executed. Is owned by the
    /// ExecutionManager instance.
    StateChangeHandler(std::map<std::string, FunctionGroup>& function_groups,
        std::set<std::shared_ptr<StartupConfiguration>>& executed_startup_configurations);

    /// @brief SetState switches the state of a FunctionGroup.
    /// @details The function can be called multiple times for the same state change.
    ///
    /// @param processed_request The request to process.
    ///
    /// @returns An optional result of the requested transition. The optional is empty if the transition is not
    /// completed yet.
    //nosal::core::Optional<nosal::exec::internal::StateClientImpl::SetStateResponse>
	    bool SetState(
        ProcessedSetStateRequest& processed_request);

    /// @brief SetCompleteState switches the state of a FunctionGroup. It blocks until the switch is done
    ///
    /// @param processed_request The request with all requested state changes to process.
    ///
    /// @returns The result of the requested transitions.
    //nosal::exec::internal::StateClientImpl::SetStateResponse::Status
	    bool SetCompleteState(
        ProcessedSetStateRequest& processed_request);

private:
    /// @brief Starts the specified Processes.
    /// @details The function can be called multiple times for starting the same Processes.
    ///
    /// @param startup_configurations The processes to start.
    /// @param processed_request The processed request that needs the given Process to start.
    ///
    /// @returns True if the start of the given Processes finished.
    bool Execute(std::vector<std::shared_ptr<StartupConfiguration>>& startup_configurations,
        ProcessedSetStateRequest& processed_request);

    /// @brief Terminates the specified Processes.
    /// @details The function can be called multiple times for terminating the same Processes.
    ///
    /// @param startup_configurations The Processes to terminate.
    /// @param processed_request The request that issued the termination request.
    ///
    /// @returns A boolean to indicate if all Processes terminated.
    bool Terminate(std::vector<std::shared_ptr<StartupConfiguration>>& startup_configurations,
        ProcessedSetStateRequest& processed_request);

    /// @brief Calculates which processes need to be started and terminated for a transition to the FunctionGroupState.
    ///
    /// @param function_group The FunctionGroup of the transition.
    /// @param state The new state.
    ///
    /// @returns The calculated transition changes.
    TransitionChanges CalculateTransitions(const FunctionGroup* function_group, const std::string& state);

    /// @brief Checks if any running processes terminated.
    void CheckProcessTerminations();

    /// @brief RemoveTerminatedProcesses removes terminated processes from executed_startup_configurations_
    void RemoveTerminatedProcesses();

    /// @brief All executed processes. The ExecutionManager instance has the ownership of the set.
    std::set<std::shared_ptr<StartupConfiguration>>& executed_startup_configurations_;

    /// @brief All FunctionGroups. The ExecutionManager instance has the ownership of the map.
    std::map<std::string, FunctionGroup>& function_groups_;
};

}  // namespace internal
}  // namespace exec
}  // namespace nosal
}  // namespace netaos

#endif  // NOSAL_EXEC_INTERNAL_STATE_CHANGE_HANDLER_H_
